#pragma once
extern "C" {
#include <f2c.h>
#include <clapack.h>
}

#include "LatoolException.h"

namespace LatoolNet {
	using namespace System;

	///
	///<summary>
	/// This class performs singular value decomposition.
	///</summary>
	///
	public ref class SingularValueDecomposition {
	private:
		SingularValueDecomposition() {};
	public:

		///
		///<summary>
		/// Decompose a matrix.  
		///</summary>
		static void Decompose(Matrix ^ a, 
													[Runtime::InteropServices::Out] Matrix^ %resultSigma,
													[Runtime::InteropServices::Out] Matrix^ %resultU,
													[Runtime::InteropServices::Out] Matrix^ %resultVT) {

			if (a->Type != MatrixType::DoubleGeneral) {
				throw gcnew LatoolException("Only general matrix is supported.");
			}
			
			DoubleGeneralMatrix ^ da = (DoubleGeneralMatrix^) a->GetInternalMatrix();

			resultSigma = gcnew Matrix(a->RowNum, a->ColNum);
			resultU = gcnew Matrix(a->RowNum, a->RowNum);
			resultVT = gcnew Matrix(a->ColNum, a->ColNum);

			da->SolveSVD(resultSigma->GetInternalMatrix(), resultU->GetInternalMatrix(), resultVT->GetInternalMatrix());

		};

		///
		///<summary>
		/// Decompose a matrix.  
		///</summary>
		static void Decompose(ComplexMatrix ^ a, 
													[Runtime::InteropServices::Out] ComplexMatrix^ %resultSigma,
													[Runtime::InteropServices::Out] ComplexMatrix^ %resultU,
													[Runtime::InteropServices::Out] ComplexMatrix^ %resultVT) {

			if (a->Type != MatrixType::ComplexGeneral) {
				throw gcnew LatoolException("Only general matrix is supported.");
			}
			
			ComplexGeneralMatrix ^ da = (ComplexGeneralMatrix^) a->GetInternalMatrix();

			resultSigma = gcnew ComplexMatrix(a->RowNum, a->ColNum);
			resultU = gcnew ComplexMatrix(a->RowNum, a->RowNum);
			resultVT = gcnew ComplexMatrix(a->ColNum, a->ColNum);

			da->SolveSVD(resultSigma->GetInternalMatrix(), resultU->GetInternalMatrix(), resultVT->GetInternalMatrix());

		};

	};

}